package vno.sci.net
{
	import com.adobe.crypto.SHA1;
	import com.hurlant.crypto.Crypto;
	import com.hurlant.crypto.hash.SHA1;
	import com.hurlant.math.BigInteger;
	import com.hurlant.util.Hex;
	
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	import flashx.textLayout.formats.BackgroundColor;
	import flashx.textLayout.operations.PasteOperation;
	
	import mx.effects.easing.Back;
	
	import net.tynril.crypto.srp6.SRP6;
	
	import system._Environment;
	
	public class Login
	{
		private var b:ByteArray= new ByteArray();
		private var bA:ByteArray = new ByteArray();
		private var socket:Socket= new Socket("127.0.0.1",3724);
		private var playerName:String = "TEST";
		private var playerPassword:String = "password";
		//5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
		private var counter:int = 0;
		
		
		private var B:ByteArray;
		private var N:ByteArray;
		private var s:ByteArray;
		
		private var B_S:String;
		private var N_S:String;
		private var S_S:String;
		private var B_S_R:String;
		private var N_S_R:String;
		private var S_S_R:String;
		
		
		public function Login()
		{
			socket.addEventListener(Event.CONNECT, onConnect);
			socket.addEventListener(ProgressEvent.SOCKET_DATA,onSocketData);
		}
		
		private function onSocketData(event:ProgressEvent):void
		{
			if(counter == 0)
			{
				++counter;
				trace("收到的数据："+socket.bytesAvailable+"b/s");
				socket.readByte();//uint8 AUTH_LOGON_CHALLENGE
				socket.readByte();//uint8 0x00
				socket.readByte();//uint8 REALM_AUTH_SUCCESS
				B = new ByteArray();
				socket.readBytes(B,0,32);//uint8 B[32]; B is an SRP6 value. It is the server's public value.
				
				
				//trace("B.toString() is " + new BigInteger(B).toString());
				//B.toString() is c252c8811f74ae8b45a146ca36d746902cd45932d080f848195a3be2c5799086
				
				
				socket.readByte();//uint8 g_les; //Length of the SRP6 g value we send the client in bytes. Always 1
				socket.readByte();//uint8 g[1]; //The SRP6 g value we send the client. Always 7
				socket.readByte();//uint8 N_len; //Lenght of the SRP6 N value we send the client. Always 32
				N = new ByteArray();
				socket.readBytes(N,0,32);//uint8 N[32]; //The SRP6 N value we send the client.
				
				
				//trace("N.toString = " + new BigInteger(N).toString());
				//N.toString  = b79b3e2a87823cab8f5ebfbf8eb10108535006298b5badbd5b53e1895e644b89
				//N is actually 894b645e89e1535bbdad5b8b290650530801b18ebfbf5e8fab3c82872a3e9bb7
				//N is actually doubleReverseString(N.toString());
				
				s = new ByteArray();
				socket.readBytes(s,0,32);//uint8 s[32]; //The SRP6 s value
				
				//trace("salt is " + new BigInteger(s).toString());
				//salt is fbea9919faffaae9f86b7eefd36e8ce872417cbabcb40ae0f347d61113efa7e7
				
				var unk:ByteArray = new ByteArray();
				socket.readBytes(unk,0,16);//uint8 unk3[16]; //a randomly generated 16 byte value.
				//trace(unk.toString());
				socket.readByte();//a single byte 0;
				
				N_S = new BigInteger(N).toString();
				B_S = new BigInteger(B).toString();
				S_S = new BigInteger(s).toString();
				
				N_S_R = doubleReverseString(N_S);
				B_S_R = doubleReverseString(B_S);
				S_S_R = doubleReverseString(S_S);
				
				var N_INT:BigInteger = new BigInteger(N);
				var B_INT:BigInteger = new BigInteger(B);
				var S_INT:BigInteger = new BigInteger(s);
				
				var a:ByteArray= new ByteArray();
				a.writeUTFBytes("1234567890123456789");
				var a_INT:BigInteger = new BigInteger(a);
				var g_INT:BigInteger = new BigInteger("7");
				
				var A_INT:BigInteger = g_INT.modPow(a_INT,N_INT);

				var hash:com.hurlant.crypto.hash.SHA1 = new com.hurlant.crypto.hash.SHA1();
				
				var aplusb:ByteArray = new ByteArray();
				aplusb.writeBytes(A_INT.toByteArray());
				aplusb.writeBytes(B_INT.toByteArray());
				
				var u:ByteArray = hash.hash(aplusb);                       //u = H(A, B)
				var I:ByteArray = hash.hash(stoba(playerName+playerPassword));   //I = sha(“username : password”)
				var x:ByteArray = hash.hash(baplus(s,I));
				var u_INT:BigInteger = new BigInteger(u);
				var x_INT:BigInteger = new BigInteger(x);
					
				//ByteArray: N B s 
				//BigInteger: g A S
				//ByteArray: a u x K I
				trace(u_INT,"\n",x_INT);
				
										
				var s1_INT:BigInteger = new BigInteger();
				s1_INT = B_INT.subtract(g_INT.modPow(x_INT,N_INT)).multiply(new BigInteger("3"));
				var s2_INT:BigInteger = new BigInteger();
				s2_INT = a_INT.add(u_INT.multiply(x_INT));
				var S_INT:BigInteger = new BigInteger();
				S_INT= s1_INT.modPow(s2_INT,N_INT);                        //S = (B - g^x*3)^(a+u*x)
				var S:ByteArray = S_INT.toByteArray();
			    trace(S_INT);
				trace(S.bytesAvailable);
				var Sodd:ByteArray = new ByteArray();
				var Seven:ByteArray = new ByteArray();
//				for (var i:int = 0; i < 16; i++)
//				{
//					Seven.writeByte(S.readByte());
//					Sodd.writeByte(S.readByte());
//				}
				
				
				
				
					
					
				var HN:BigInteger = new BigInteger(hash.hash(N));
				var HG:BigInteger = new BigInteger(hash.hash(g_INT.toByteArray()));
				var HNxorHG:BigInteger = new BigInteger(HN.xor(HG));
//				var HI:BigInteger = new BigInteger(hash.hash(stoba()));
				
			    
					
					
					
					
					
					
					
				
				var test:net.tynril.crypto.srp6.SRP6 = new SRP6();			
				
				//step 0; Initialize this SRP6 instance with the given arithmetic constants, or with the default constants. 
//				test.initialize(N_S,"7","3");
				test.initialize(N_S_R,"7","3");
						
				//step 1; Compute the client token 'A' to be sent to the server along with the username.
				var A_C:String = test.computeClientToken();//A_C[32];
				var A_C_R:String = doubleReverseString(A_C);
				
				//step 2; Received the salt s and the B token from the server.

//				test.receiveSaltAndServerToken(S_S,B_S);//both s and B has not been reversed.
				test.receiveSaltAndServerToken(S_S_R,B_S_R);//both s and B has been reversed.

				
				//step 3 Computes the key proof to be sent to the server,
				//using all previously set data and the password given by the user.
				
				var keyProff:String = test.computeKeyProof(playerName,playerPassword);//keyProof[20]
//				var keyProff_R:String = doubleReverseString(keyProff);

				
							
//				bA.endian = Endian.LITTLE_ENDIAN;
//				bA.writeByte(1);//Cmd must be 1--by Scinart
//				
////				bA.writeBytes(Hex.toArray(A_C));//A[32] //The client SRP6 A value ( public client value ).
////				bA.writeBytes(Hex.toArray(keyProff));//M[20] The client's SRP6 M value.待比较的最终值
//				bA.writeBytes(Hex.toArray(A_C_R));//A[32] //The client SRP6 A value ( public client value ).
//				bA.writeBytes(Hex.toArray(keyProff_R));//M[20] The client's SRP6 M value.待比较的最终值
//				
//				//crc_hash[20], doesn't seem to be used.
//				
//				bA.writeByte(0x50);
//				bA.writeByte(0x92);
//				bA.writeByte(0xE0);
//				bA.writeByte(0xC0);
//				bA.writeByte(0xE5);
//				bA.writeByte(0x4A);
//				bA.writeByte(0xE5);
//				bA.writeByte(0x1B);
//				bA.writeByte(0xBD);
//				bA.writeByte(0xB4);
//				bA.writeByte(0x96);
//				bA.writeByte(0x59);
//				bA.writeByte(0x63);
//				bA.writeByte(0x17);
//				bA.writeByte(0x43);
//				bA.writeByte(0x75);
//				bA.writeByte(0x41);
//				bA.writeByte(0x07);
//				bA.writeByte(0x4C);
//				bA.writeByte(0x94);
//				
//				bA.writeByte(0);//number_of_keys, It also seems to be always 0
//				bA.writeByte(0x00);//securityFlags; 0x00-0x04
////				
////				bA.writeByte(0);
////				bA.writeByte(0);
////				bA.writeByte(0);
////				bA.writeByte(0);
//				
//				trace(bA.length);
//				
//				socket.writeBytes(bA);
//				socket.flush();
			}
//			else if(counter == 1)
//			{
//				++counter;
//				trace("收到的数据："+socket.bytesAvailable+"b/s");
//				trace(socket.readByte());//uint8 cmd
//				trace(socket.readByte());//uint8 error
//				trace(socket.readByte());//uint8 error
//				socket.writeBytes(bA);
//				socket.flush();
//				
//			}
//			else
//			{
//				trace("收到的数据："+socket.bytesAvailable+"b/s");
//				trace(socket.readByte());//uint8 cmd
//				trace(socket.readByte());//uint8 error
//				trace(socket.readByte());//uint8 error
//			}
			
		}
		private function baplus(a:ByteArray, b:ByteArray):ByteArray
		{
			var c:ByteArray =new ByteArray();
			c.writeBytes(a);
			c.writeBytes(b);
			return c;
		}
		private function stoba(s:String):ByteArray
		{
			var c:ByteArray =new ByteArray();
			c.writeUTFBytes(s);
			return c;
		}
		private function hextoba(s:String):ByteArray
		{
			var c:BigInteger = new BigInteger(s);
			return c.toByteArray();
		}
		private function onConnect(event:Event):void
		{
			
			var usernameLength:int = playerName.length;
			b.endian = Endian.LITTLE_ENDIAN;
			b.writeByte(0x00);//cmd
			b.writeByte(0x08);//error
			b.writeByte(30+usernameLength);//size
			b.writeByte(00);//size
			b.writeUTFBytes("WoW");//gamename[4] //4 byte C-String, containing the String "WoW\0"
			b.writeByte(0);
			b.writeByte(0x03);//version1
			b.writeByte(0x03);//version2
			b.writeByte(0x05);//version3
			b.writeByte(0xc3);//build
			b.writeByte(0x34);//build
			b.writeUTFBytes("68x"); //Platform the client is running on, reversed C-String ( "68x\0" for x86 )
			b.writeByte(0);
			b.writeUTFBytes("niW");//OS the client is running on, reversed C-String ( "niW\0" for Windows )
			b.writeByte(0);
			b.writeUTFBytes("NChz");//Locale of the client, reversed C-String ( "SUne" for enUS )
			//b.writeUnsignedInt(8*3600);
			b.writeByte(0xe0);//time-
			b.writeByte(0x01);//zone
			b.writeByte(0x00);
			b.writeByte(0x00);
			b.writeUnsignedInt(0x0100007F);//IP address of the client in binary format
			b.writeByte(usernameLength); //Length of the Identity ( user name ) in characters
			b.writeUTFBytes(playerName); //The Identity string ( user name )
			socket.writeBytes(b);
			socket.flush();
		}
		
		/**
		 * Reverses the order of the bytes in the specified range.
		 *  
		 * @param byteArray The ByteArray to reverse.
		 * 
		 * @throws ArgumentError <code>byteArray</code> parameter is <code>null</code>.
		 * 
		 * @throws RangeError Thrown in the following situations:<ul>
		 * <li>the length of <code>byteArray</code> is less than zero.</li>
		 * </ul>
		 */		
		public function doubleReverseString(string:String):String
		{
			// from "a1b2c3" to "c3b2a1"
			var doubleReversed:String = new String();
			//string.length must be even;
			for (var i:int = 0; i < string.length; i+=2)
			{
				doubleReversed = string.slice(i,i+2).concat(doubleReversed);
			}
			return doubleReversed;
		}
	}
}